package service

import (
	"fmt"
	"gitee.com/MrDaiM/generate-project/tpls"
	"github.com/xlab/treeprint"
	"os"
	"path/filepath"
	"strings"
	"text/template"
	"time"
)

type Builder struct {
	options *Options
}

func NewBuilder(options *Options) *Builder {
	b := &Builder{
		options: options,
	}
	b.addWrapFile()
	return b
}

func (b *Builder) addWrapFile() {
	b.options.AddWrapFile(
		NewWrapFile("main.go", tpls.MainAPI),
		NewWrapFile("handler/"+b.options.Alias+"Handler.go", tpls.MainAPI),
		NewWrapFile("plugin/hystrix/hystrix.go", tpls.Hystrix),
		NewWrapFile("domain/model/"+b.options.Alias+".go", tpls.DomainModel),
		NewWrapFile("domain/repository/"+b.options.Alias+"_repository.go", tpls.DomainRepository),
		NewWrapFile("domain/service/"+b.options.Alias+"_data_service.go", tpls.DomainService),
		NewWrapFile("proto/"+b.options.Alias+"/"+b.options.Alias+".proto", tpls.ProtoSRV),
		NewWrapFile("filebeat.yml", tpls.Filebeat),
		NewWrapFile("Makefile", tpls.Makefile),
		NewWrapFile("README.md", tpls.Readme),
		NewWrapFile(".gitignore", tpls.GitIgnore),
		NewWrapFile("go.mod", tpls.Module),
	)

	fmt.Println(b)
}

func (b *Builder) build() error {
	// check the files
	if _, err := os.Stat(b.options.Dir); !os.IsNotExist(err) {
		fmt.Printf("%s 目录已经存在， 无法创建！请删除后重新创建", b.options.Dir)
		return fmt.Errorf("%s already exists", b.options.Dir)
	}

	fmt.Printf("创建初始化项目%s\n\n", b.options.Alias)

	// - w
	// 生成目录树
	tree := treeprint.New()

	for _, file := range b.options.WrapFiles {
		f := filepath.Join(b.options.Dir, file.Path) // 绝对路径
		dir := filepath.Dir(f)

		// 创建文件
		if _, err := os.Stat(dir); os.IsNotExist(err) {
			if err := os.MkdirAll(dir, 0755); err != nil {
				fmt.Println(err)
				return err
			}
		}

		// 记录目录结构，生成目录树
		b.addFileToTree(tree, file.Path)

		// 将模版中的内容写入文件

		if err := b.write(f, file.Tmpl); err != nil {
			fmt.Println(err)
			return err
		}

	}

	// 输出目录结构
	fmt.Println(tree.String())

	// 输出介绍
	for _, comment := range b.options.Comments {
		fmt.Println(comment)
	}

	<-time.After(time.Millisecond * 250)
	fmt.Printf("\n********************恭喜！项目初始化成功！ ***********************\n")
	return nil

}

func (b *Builder) write(file string, tmpl string) error {

	// 函数名 - 函数具体的实现 提供给模版使用
	funcMap := template.FuncMap{
		"title": func(s string) string {
			return strings.ReplaceAll(strings.Title(s), "-", "") // 每个单词的首字母转换为大写。
		},
		"dehyphen": func(s string) string {
			return strings.ReplaceAll(s, "-", "")
		},
		"lower": func(s string) string {
			return strings.ToLower(s)
		},
	}
	// 创建文件
	f, err := os.Create(file)
	if err != nil {
		return err
	}
	defer f.Close()

	t, err := template.New("f").Funcs(funcMap).Parse(tmpl)
	if err != nil {
		return err
	}
	err = t.Execute(f, b.options)
	return err
}

func (b *Builder) addFileToTree(tree treeprint.Tree, path string) {

	// plugin/hystrix/hystrix.go
	// github
	// 根据路径先创建目录，最后在创建文件
	splits := strings.Split(path, "/")
	curr := tree
	for i := 0; i < len(splits)-1; i++ {
		t := curr.FindByValue(splits[i])
		if t != nil { // 之前的节点已存在
			curr = t // 递归到下一个
		} else {
			// 创建branch
			curr = curr.AddBranch(splits[i])
		}
	}
	// 以上目录创建好了，开始创建最后一个文件
	if curr.FindByValue(splits[len(splits)-1]) == nil {
		curr.AddNode(splits[len(splits)-1])
	}
}
